/*
*    Phantom v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include ".\sockcmd.h"
#include ".\ssi_socket.h"


#include <stdio.h>
#include <string>
//using std::string;

CSockCmd::CSockCmd(void)
: ID(0)
, Size(0)
, Data(0)
, bValidSequence(false)
{
	SequenceCtr = 0;
	ConnectionID = 0;
}

CSockCmd::CSockCmd(CSockCmd& Other)
{
	Data = 0;
	Size = 0;
	ID = 0;
	Clear();
	if(Other.Data){
		Data = strdup(Other.Data);
	}
	ID = Other.ID;
	Size = Other.Size;
	SequenceCtr = Other.SequenceCtr;
	ConnectionID = Other.ConnectionID;
}

CSockCmd::~CSockCmd(void)
{
	Clear();
}

void CSockCmd::Clear(void)
{
	if(Data){
		delete [] Data;
		Data = 0;
	}
	ID = 0;
	Size = 0;
	//SequenceCtr = 0;
	ConnectionID = 0;
}

CSockCmd& CSockCmd::operator=(CSockCmd& Other){
	Clear();
	if(Other.Data){
		Data = strdup(Other.Data);
	}
	ID = Other.ID;
	Size = Other.Size;
	return *this;
}

void CSockCmd::Set(int InID, int InSize, const char* InData)
{
	Clear();
	ID = InID;
	Size = InSize;
	Data = new char[InSize+1];
	Data = (char*)memcpy((void*)Data, (const void*)InData, InSize);
	Data[InSize] = 0;
	//Data = strdup(InData);   // strdup doesnt seem to work here... added false data
}

int CSockCmd::ReadMe(CSocketSSI& theSocket)
{
	Clear();

	CSockCmd Ret;
	int cmd_id = 0;
	int data_size = 0;

	int OldCtr = SequenceCtr;

	if(!theSocket.ReadData((char*)&ID, sizeof(ID))){
		return 0;
	}

	if(!theSocket.ReadData((char*)&ConnectionID, sizeof(ConnectionID))){
		return 0;
	}

	if(!theSocket.ReadData((char*)&SequenceCtr, sizeof(SequenceCtr))){
		return 0;
	}

	if(!theSocket.ReadData((char*)&Size, sizeof(Size))){
		return 0;
	}

	if(Size > 0){
		Data = new char[Size+1];
		if(!theSocket.ReadData(Data, Size)){
			return 0;
		}
		Data[Size] = 0;
	}

	if(SequenceCtr != OldCtr){
		bValidSequence = false;
	}else{
		bValidSequence = true;
	}

	if(0){
		if(Size > 0){
			printf("Command Read: [%d] [%d] [%d] Data = %s\n", ID, SequenceCtr, Size, Data);  // KEEP PRINT
		}else{
			printf("Command Read: [%d] [%d] [%d] Data = {null}\n", ID, SequenceCtr, Size);    // KEEP PRINT
		}
	}

  SequenceCtr++;

	//printf("Sequence: %d\n", SequenceCtr);

	return 1;
}

int CSockCmd::SendMe(CSocketSSI& theSocket)
{
	CSockCmd Ret;
	int data_size = sizeof(ID) + sizeof(ConnectionID) + sizeof(SequenceCtr) + sizeof(Size) + Size;
	int offset = 0;
	char* data_buf = new char[data_size];
	memcpy(data_buf + offset, &ID, sizeof(ID));
	offset += sizeof(ID);

	memcpy(data_buf + offset, &ConnectionID, sizeof(ConnectionID));
	offset += sizeof(ConnectionID);

	memcpy(data_buf + offset, &SequenceCtr, sizeof(SequenceCtr));
	offset += sizeof(SequenceCtr);

	memcpy(data_buf + offset, &Size, sizeof(Size));
	offset += sizeof(Size);

	memcpy(data_buf + offset, Data, Size);

	if(0){
		if(Size > 0){
			printf("Command Sent: [%d] [%d] [%d] Data = %s\n", ID, SequenceCtr, Size, Data);  // KEEP PRINT
		}else{
			printf("Command Sent: [%d] [%d] [%d] Data = {null}\n", ID, SequenceCtr, Size);  // KEEP PRINT
		}
	}

	if(theSocket.SendData(data_buf, data_size)){
		SequenceCtr++;
		delete [] data_buf;
		return 1;
	}else{
		delete [] data_buf;
		return 0;
	}
}

bool CSockCmd::IsValidSequence(void)
{
	return bValidSequence;
}
